
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

using Swaf.BizObj;
using Swaf.Container;
using Swaf.Security;

namespace Swaf.Gui
{
	public abstract class BaseBusinessProcess : IBusinessProcess, IBusinessProcessInternal
	{
		protected ActiveBizProc m_procState;
		protected IBizObj m_currentBizObj;
		protected IBizObjList m_bizobjs;
		protected IBizObj m_filterSortCriteria = null;
		protected Actions m_actions = new Actions();

		protected bool m_retrievedBizObjList = false;
		protected bool m_retrievedCurrentBizObj = false;
		protected bool m_hadValidationErrors = false;
		protected bool m_beenInitialized = false;

		protected string m_getBizObjDetailsRule;
		protected string m_getBizObjListRule;
		protected string m_getMasterBizObjListRule;
		protected string m_deleteBizObjRule;
		protected string m_updateBizObjRule;
		protected string m_bizObjListCheckedChangedRule;

		protected MasterDataOption m_masterDataOption = MasterDataOption.unknown;


		public BaseBusinessProcess(ActiveBizProc procState)
		{
			m_procState = procState;
		}

		public virtual void initialize()
		{
			setupActions();
			setupRuleNames();
			updateActionState();
			m_beenInitialized = true;
		}

		#region IBusinessProcess Members

		public string Id
		{
			get { return State.Id; }
		}

		public virtual IBizObj CurrentBizObj
		{
			get
			{
				if (State.InProgressAddBizObj != null)
					return State.InProgressAddBizObj;
				if (m_currentBizObj == null)
					getCurrentBizObj();
				return m_currentBizObj;
			}
		}

		public IBizObjList SourceBizObjs
		{
			get
			{
				if (m_bizobjs == null)
					getBizObjList();
				return m_bizobjs;
			}
		}

		public MasterDataOption MasterDataOption
		{
			get
			{
				if (m_masterDataOption == MasterDataOption.unknown)
				{
					if (!Cmn.IsEmpty(m_getMasterBizObjListRule))
						m_masterDataOption = MasterDataOption.listFromRule;
					else if (m_procState.get("masterList") as IBizObjList != null)
						m_masterDataOption = MasterDataOption.listFromParentBizProc;
					else
						m_masterDataOption = MasterDataOption.none;
				}
				return m_masterDataOption;
			}
		}

		protected virtual void setupMasterBizObjList()
		{
			IBizObjList masterList = null;
			IBizObjList baseList = m_bizobjs;

			if (baseList != null && MasterDataOption != MasterDataOption.none)
			{

				if (m_masterDataOption == MasterDataOption.listFromRule)
				{
					object mlpid = m_procState.get("mlpid");
					IResults rc = App.ruleMgr.execute(m_getMasterBizObjListRule, getMasterBizObjListBizRuleParams(mlpid));
					if (rc.CallResults is IBizObjList)
						masterList = rc.CallResults as IBizObjList;
				}
				else
					masterList = m_procState.get("masterList") as IBizObjList;

				Debug.Assert(masterList != null);
				prepareForMasterList(ref masterList, ref baseList);
				IBizObjList newBizObjs = new MasterBaseBizObjList(MasterDataDisplayOption, masterList, baseList, (string)State.State.get("baseListFieldNameforMaster"), createNewBizObj);
				m_bizobjs = newBizObjs;
			}
		}

		protected virtual MasterBaseBizObjListDisplayOption MasterDataDisplayOption
		{
			get
			{
				MasterBaseBizObjListDisplayOption op = MasterBaseBizObjListDisplayOption.blended;
				object v = State.State.get("masterDataDisplay");
				if (v is string)
					State.State.put("masterDataDisplay", op = (MasterBaseBizObjListDisplayOption)Enum.Parse(typeof(MasterBaseBizObjListDisplayOption), (string)v));
				else if (v is MasterBaseBizObjListDisplayOption)
					op = (MasterBaseBizObjListDisplayOption)v;
				return op;
			}
			set
			{
				State.State.put("masterDataDisplay", value);
			}
		}

		protected virtual void prepareForMasterList(ref IBizObjList masterList, ref IBizObjList baseList)
		{
		}

		protected virtual object[] getMasterBizObjListBizRuleParams(object mlpid)
		{
			return new object[] { mlpid };
		}

		protected int calculatePagingSize(List<IBizObjListDisplay> listDisplays)
		{
			int numPerPage = 0;
            foreach (IBizObjListDisplay d in listDisplays)
            {
                int maxEl = -1;
                if(int.TryParse(d.MaxElements, out maxEl) && maxEl > 0)
                    numPerPage += maxEl;
            }
			return numPerPage;
		}

		public virtual void showData(ForceLevel level)
		{
			if (State.State.get("itsMe") is bool && (bool)State.State.get("itsMe"))
				return;
			if (level == ForceLevel.mustShowForceDataRetrieval)
			{
				m_retrievedBizObjList = false;
				m_retrievedCurrentBizObj = false;
			}
			string myId = m_procState.BizProc.Id;
			BaseBusinessProcess.incrementCount(myId);


			updateActionState();
			if ((level != ForceLevel.showIfHasData && level != ForceLevel.mustShowGetDetailsDataIfNeeded) || (level == ForceLevel.showIfHasData && m_bizobjs != null))
			{
				//The following call could be what actually creates the list controls.  When in ajax event procesing
				//The widgets are not created unless specifically referenced.  
				List<IBizObjListDisplay> listDisplays = m_procState.getListDisplays();
				if (listDisplays != null && SourceBizObjs != null)
				{
					IBizObjCursor cur = SourceBizObjs.createCursor();
					List<IPaginationDisplay> pagers = m_procState.getPagerDisplays();
					if (pagers != null)
					{
						int pagesize = calculatePagingSize(listDisplays);
						
						object pid = m_procState.get("pid");
						if (pid != m_procState.get("lastPid"))
						{
							CurrentPage = 0;
							m_procState.put("lastPid", pid);
						}

						foreach (IPaginationDisplay pager in pagers)
							pager.setupPagination(SourceBizObjs.numElements, pagesize, CurrentPage);

						if(cur.numElements > 0)
							cur.moveTo(CurrentPage * pagesize);
					}
					foreach (IBizObjListDisplay listDisp in listDisplays)
					{
						//if (pagers == null)
						//	cur.moveFirst();
						listDisp.EditPrivilege = CanEdit ? CurrentEditPrivilege : Privileges.ReadOnly;
						IBizObjList bizobjs = SourceBizObjs;
						if (bizobjs is MasterBaseBizObjList)
						{
							MasterBaseBizObjList mb = (MasterBaseBizObjList)bizobjs;
							listDisp.setSelectedBizObjs(mb.BaseList);
						}
						listDisp.SelectedBizObjKeyValue = CurrentBizObjKeyValue;
						listDisp.showBizObjs(cur);
					}
				}
			}
			if (level == ForceLevel.mustShowForceDataRetrieval || 
				level == ForceLevel.mustShowGetDetailsDataIfNeeded ||
				level == ForceLevel.mustShowGetAllDataIfNeeded ||
                (/*m_procState.ForceShowBizObj &&*/ (level == ForceLevel.showIfHasData && (m_currentBizObj != null || State.InProgressAddBizObj != null))))
			{
			//	if (CurrentBizObj != null)
			//	{
					//updateActionState();
					//The following call could be what actually creates the display controls.  When in ajax event procesing
					//The widgets are not created unless specifically referenced.  
					List<IBizObjDisplay> detailDisplays = m_procState.getDetailsDisplays();
					if (detailDisplays != null)
						foreach (IBizObjDisplay disp in detailDisplays)
						{
							disp.EditPrivilege = CanEdit ? CurrentEditPrivilege : Privileges.ReadOnly;
							disp.displayBizObj(CurrentBizObj);
						}
			//	}
			}

            basicLog("showData");
            
            //This code just ensures the buttons are active and can update thier state in the browser.
			m_procState.getActionTriggers();

            //if (level == ForceLevel.mustShowForceDataRetrieval)
            //    forceChildBizProcUpdates();
		}

		protected virtual object CurrentBizObjKeyValue 
		{ 
			get 
			{ 
				object v = m_currentBizObj==null?m_procState.get("id"):m_currentBizObj.KeyValue;
				if(v == null)
					v = getCurrentBizObjId();
				//if (!m_retrievedCurrentBizObj && CurrentBizObj != null)
				//	v = CurrentBizObj.KeyValue;
				return v;
			} 
		}

		public Actions Actions
		{
			get { return m_actions; }
		}

		public bool RetrievedBizObjList
		{
			get { return m_retrievedBizObjList; }
		}

		public bool RetrievedCurrentBizObj
		{
			get { return m_retrievedCurrentBizObj; }
		}

		public int CurrentPage
		{
			get
			{
				int currentPage = 0;
				if (State.State.containsField("CurrentPage"))
					currentPage = (int)State.State.get("CurrentPage");
				return currentPage;
			}
			set
			{
				State.State.put("CurrentPage", value);
			}
		}

		#endregion

		protected BizProcOfflineState State { get { return m_procState.OfflineState; } }

		protected virtual object getCurrentBizObjId()
		{
			object bizObjId = null;
			try
			{
				bizObjId = m_procState.get("id");
				int numObjs = -1;
				if (bizObjId == null && SourceBizObjs != null && (numObjs = SourceBizObjs.numElements) != 0)
					bizObjId = SourceBizObjs[0].KeyValue;
			}
			catch (Exception e)
			{
				processSystemException(e);
			}
			return bizObjId;
		}

		protected virtual bool shouldCallGetBizObjDetailsRule(object[] ruleParams)
		{
			return ruleParams != null;
		}

		public virtual IBizObj getBizObj(object keyValue)
		{
			if (!Cmn.IsEmpty(m_getBizObjDetailsRule))
			{
				string id = m_procState.BizProc.Id;
				string id2 = Id;
				object[] ruleParams = getDetailsBizRuleParameters(keyValue);
				IResults rc = App.ruleMgr.execute(m_getBizObjDetailsRule, ruleParams);
				if (rc.ExceptionInfo != null)
				{
					//TODO: log exception info
				}
				return rc.CallResults as IBizObj;
			}
			return null;
		}

		protected virtual void getCurrentBizObj()
		{
            try
            {
                ParentBizProcInfo dpinfo = getCompletlyDependentParent();
                if (dpinfo != null && dpinfo.DataId.ToLower() == "current")
                {
                    IBizObj pobj = m_procState.get(dpinfo.DataId) as IBizObj;
                    if ((m_currentBizObj = pobj) != null)
                    {
                        m_retrievedCurrentBizObj = true;
                        return;
                    }
                }
                object bizObjId = getCurrentBizObjId();

                if (/*bizObjId != null && */m_getBizObjDetailsRule != null)
                {
                    object[] ruleParams = getDetailsBizRuleParameters(bizObjId);
                    if (shouldCallGetBizObjDetailsRule(ruleParams))
                        m_currentBizObj = getBizObj(bizObjId);
                    m_retrievedCurrentBizObj = true;
                }
                if (m_currentBizObj == null && bizObjId != null && SourceBizObjs != null)
                {
                    if (SourceBizObjs is MasterBaseBizObjList)
                        m_currentBizObj = ((MasterBaseBizObjList)SourceBizObjs).search(SourceBizObjs.objectType.KeyFieldNames, bizObjId, false, true);
                    else
                        m_currentBizObj = SourceBizObjs.search(SourceBizObjs.objectType.KeyFieldNames, bizObjId);
                    if (m_currentBizObj != null)
                    {
                        m_retrievedCurrentBizObj = true;
                    }
                }
                if (m_currentBizObj == null && m_bizobjs != null && m_bizobjs.numElements != 0)
                {
                    m_currentBizObj = m_bizobjs[0];
					m_retrievedCurrentBizObj = true;
                }

				if (m_currentBizObj != null)
				{
					if (m_procState.get("id") != null)
						m_procState.put("prevId", m_procState.get("id"));
					m_procState.put("id", m_currentBizObj.KeyValue);
				}

                if (m_retrievedCurrentBizObj && m_currentBizObj != null && m_procState.get("id") != null && !m_procState.get("id").Equals(m_procState.get("prevId")))
                    clearDependentChildBizProcs();
                //{
                //    List<ActiveBizProc> children = m_procState.BPC.getDependentBizProcs(State.Id);
                //    if (children != null)
                //        foreach (ActiveBizProc child in children)
                //        {
                //            foreach (ParentBizProcInfo pinfo in child.OfflineState.ParentBizProcs.Values)
                //                if (pinfo.ParentId == Id && (pinfo.ParentSelectedBizObjFieldName == null || CurrentBizObj.get(pinfo.ParentSelectedBizObjFieldName) != pinfo.ParentSelectedBizObjFieldValueCache))
                //                {
                //                    pinfo.ParentSelectedBizObjFieldValueCache = null;
                //                    if (pinfo.ParentId == Id && "pid".CompareTo(pinfo.DataId) == 0)
                //                        child.put("id", null);
                //                }
                //            //foreach (ParentBizProcInfo pinfo in child.OfflineState.ParentBizProcs.Values)
                //            //    if (pinfo.ParentId == Id && (pinfo.ParentSelectedBizObjFieldName == null || CurrentBizObj.get(pinfo.ParentSelectedBizObjFieldName) != pinfo.ParentSelectedBizObjFieldValueCache))
                //            //        child.BizProc.showData(ForceLevel.mustShowForceDataRetrieval);
                //        }

                //}
            }
            catch (Exception e)
            {
                processSystemException(e);
            }
		}

        protected internal virtual void clearDependentChildBizProcs()
        {
            basicLog("clearDependentchildBizProcs");
            List<ActiveBizProc> children = m_procState.BPC.getDependentBizProcs(Id);
            if (children != null)
                foreach (ActiveBizProc child in children)
                {
                    foreach (ParentBizProcInfo pinfo in child.OfflineState.ParentBizProcs.Values)
                        if (pinfo.ParentId == Id)// && (pinfo.ParentSelectedBizObjFieldName == null || CurrentBizObj == null || CurrentBizObj.get(pinfo.ParentSelectedBizObjFieldName) != pinfo.ParentSelectedBizObjFieldValueCache))
                        {
                            App.Log.println(Swaf.Logging.LoggingLevels.Medium, "Clearing BizProc cache info. BizProc.Id='{0}' BizProc.ParentId='{1}' PrevCachedValue='{2}'",
                                child.BizProc.Id, pinfo.ParentId, pinfo.ParentSelectedBizObjFieldValueCache);

                            pinfo.ParentSelectedBizObjFieldValueCache = null;
                            if (pinfo.ParentId == Id && "pid".CompareTo(pinfo.DataId) == 0)
                                child.put("id", null);
                        }

                    if (child.BizProc is BaseBusinessProcess)
                    {
                        ((BaseBusinessProcess)child.BizProc).clearRetrievedData();
                        ((BaseBusinessProcess)child.BizProc).clearDependentChildBizProcs();

                    }
                    //child.BizProc.showData(ForceLevel.mustShowForceDataRetrieval);
                }
        }

        public virtual void clearRetrievedData()
        {
            m_retrievedBizObjList = false;
            m_retrievedCurrentBizObj = false;
            m_bizobjs = null;
            m_currentBizObj = null;
        }

		protected virtual void processSystemException(Exception e)
		{
			displayMessage("SystemFailure");
		}

		public virtual IBizObj FilterSortCriteria
		{
			get
			{
				if (m_filterSortCriteria != null)
					return m_filterSortCriteria;
				if ((m_filterSortCriteria = m_procState.OfflineState.State.get("fsCritera") as IBizObj) != null)
					return m_filterSortCriteria;

				ActiveBizProc filterSortParent = m_procState.getParentBizProc("filterSort");
				IBizObj filterSortCriteria = null;
				if (filterSortParent != null)
				{
					filterSortParent.BizProc.updateBizObj(true);
					IBizObj saveInfo = filterSortParent.BizProc.CurrentBizObj;
					if (saveInfo != null)
						filterSortCriteria = saveInfo.get("options") as IBizObj;
				}
				return filterSortCriteria;
			}
			set
			{
				m_filterSortCriteria = value;
				m_procState.OfflineState.State.put("fsCritera", value);
			}
		}

		protected virtual void getBizObjList()
		{
			try
			{
				ParentBizProcInfo pinfo = getCompletlyDependentParent();
				if (pinfo != null)
				{
					IBizObjList plist = m_procState.get(pinfo.DataId) as IBizObjList;
					m_bizobjs = plist;
				}
				else if (m_getBizObjListRule != null)
				{
					object[] parentBizObjIds = null;
					object rawPid = m_procState.get("pid");
					if (rawPid is string)
					{
						string pid = (string)rawPid;
						if (pid.IndexOf(',') != -1)
							parentBizObjIds = pid.Split(',');
					}
					if (parentBizObjIds == null)
						parentBizObjIds = new object[] { rawPid };

					IBizObj filterSortCriteria = FilterSortCriteria;
					foreach (object parentBizObjId in parentBizObjIds)
					{
						if (shouldCallGetBizObjListRule(parentBizObjId))
						{
							IResults rc = App.ruleMgr.execute(m_getBizObjListRule, getBizObjListRuleParameters(parentBizObjId, filterSortCriteria));
							if (rc.ExceptionInfo != null)
							{
								//TODO: log exception info 
							}
							m_bizobjs = getListFromBizRuleResults(rc);
						}
						if (m_bizobjs != null && m_bizobjs.numElements > 0)
							break;
					}

					m_retrievedBizObjList = true;
				}
				setupMasterBizObjList();
			}
			catch (Exception e)
			{
				processSystemException(e);
			}
		}

		protected virtual IBizObjList getListFromBizRuleResults(IResults rc)
		{
			return rc.CallResults as IBizObjList;
		}

		protected virtual bool shouldCallGetBizObjListRule(object parentBizObjId)
		{
			bool callRule = true;
			if (parentBizObjId == null)
			{
				callRule = false;
				List<string> keys = m_procState.OfflineWidgetKeys;
				WidgetOfflineState wstate = null;
				foreach (string k in keys)
					if (m_procState.BPC.PageState.WidgetStates.TryGetValue(k, out wstate))
						foreach (string parentId in wstate.ParentBizProcIds)
							if (wstate.BizProcWidgetType == BizProcWidgetType.list && m_procState.OfflineState.Id.CompareTo(parentId) == 0)
								return true;
			}
			return callRule;
		}

		public virtual void bizObjCheckedChanged(IBizObjList uncheckedElements, IBizObjList checkedElements)
		{
			ParentBizProcInfo pinfo = getCompletlyDependentParent();
			if (pinfo != null)
			{
				IBizObjList plist = m_procState.get(pinfo.DataId) as IBizObjList;
				if (plist != null)
				{
					if (checkedElements != null)
						foreach (IBizObj ce in checkedElements)
							plist.Add(ce);
					if(uncheckedElements != null)
						foreach (IBizObj uce in uncheckedElements)
						{
							for(int p = 0; p < plist.numElements;p++)
								if (((IComparable)plist[p].KeyValue).CompareTo(uce.KeyValue) == 0)
								{
									plist.removeAt(p);
									break;
								}
						}
				}
			}
			else if (m_bizObjListCheckedChangedRule != null)
			{
				object parentBizObjId = m_procState.get("pid");
				IResults rc = App.ruleMgr.execute(m_bizObjListCheckedChangedRule,
						getBizObjCheckedChangedBizRuleParameters(parentBizObjId, uncheckedElements, checkedElements));
				if (rc.ExceptionInfo != null)
					throw rc.ExceptionInfo;
			}
		}

		protected virtual object[] getBizObjCheckedChangedBizRuleParameters(object parentBizObjId, IBizObjList uncheckedElements, IBizObjList checkedElements)
		{
			return new object[] {parentBizObjId, uncheckedElements, checkedElements };
		}

		protected virtual object[] getDetailsBizRuleParameters(object keyValue)
		{
			return new object[] { keyValue };
		}

		protected virtual object[] getBizObjListRuleParameters(object parentId, IBizObj filterSort)
		{
			if (filterSort == null)
				return new object[] { parentId };
			else
				return new object[] { parentId, filterSort };
		}

		protected virtual object[] getDeleteRuleParameters(object bizObjKey)
		{
			return new object[] { bizObjKey };
		}

		protected virtual object[] getUpdateBizRuleParameters(IBizObj bizObj)
		{
			return new object[] { bizObj };
		}

		protected virtual bool UsingEditModeForEdits
		{
			get
			{
				return State.State.get("EditModeSessionKey") is string;
			}
		}

		public virtual bool CanEdit
		{
			get
			{
				bool e = CurrentEditPrivilege >= Privileges.Edit;
				if (e && UsingEditModeForEdits)
					e = Cmn.IsTrue(App.sessionData[State.State.get("EditModeSessionKey")]);
				return e;
			}
		}

		protected abstract Privileges CurrentEditPrivilege { get;}

		public virtual void updateActionState()
		{
			Privileges curPriv = CurrentEditPrivilege;

			((GenericAction)Actions["SwitchEdit"]).Availability = 
				CurrentEditPrivilege >= Privileges.Edit?ActionAvailability.enabled:ActionAvailability.none;
			((GenericAction)Actions["MasterDataOption"]).Availability = (MasterDataOption > MasterDataOption.none) ? ActionAvailability.enabled : ActionAvailability.none;
			if (CanEdit)
			{

				bool isNew = State.InProgressAddBizObj != null;
				((GenericAction)Actions["DeleteBizObj"]).Availability =
					(isNew || curPriv == Privileges.None) ? ActionAvailability.none :
					(curPriv >= Privileges.Delete) ? ActionAvailability.enabled : ActionAvailability.disabled;
				((GenericAction)Actions["AddBizObj"]).Availability =
					(isNew || curPriv == Privileges.None) ? ActionAvailability.none :
					(curPriv >= Privileges.Add) ? ActionAvailability.enabled : ActionAvailability.disabled;
				((GenericAction)Actions["CancelEdits"]).Availability = isNew ? ActionAvailability.enabled : ActionAvailability.none;

				((GenericAction)Actions["UpdateBizObj"]).Availability =
					(curPriv == Privileges.None) ? ActionAvailability.none :
					(curPriv >= Privileges.Edit) ? ActionAvailability.enabled : ActionAvailability.disabled;
			}
			else
			{
				((GenericAction)Actions["DeleteBizObj"]).Availability = ActionAvailability.none;
				((GenericAction)Actions["AddBizObj"]).Availability = ActionAvailability.none;
				((GenericAction)Actions["UpdateBizObj"]).Availability = ActionAvailability.none;
				((GenericAction)Actions["CancelEdits"]).Availability = ActionAvailability.none;
			}
			if (m_retrievedBizObjList)
			{
				bool moreThanOneBizObj = m_bizobjs != null && m_bizobjs.numElements > 1;
				((GenericAction)Actions["MoveToFirst"]).Availability = moreThanOneBizObj ? ActionAvailability.enabled : ActionAvailability.none;
				((GenericAction)Actions["MoveToLast"]).Availability = moreThanOneBizObj ? ActionAvailability.enabled : ActionAvailability.none;
				((GenericAction)Actions["MoveNext"]).Availability = moreThanOneBizObj ? ActionAvailability.enabled : ActionAvailability.none;
				((GenericAction)Actions["MovePrev"]).Availability = moreThanOneBizObj ? ActionAvailability.enabled : ActionAvailability.none;
			}
		}

		public virtual IBizObj selectBizObj(object keyValue, object source)
		{
			IBizObj selected = setupSelectedBizObj(keyValue, source);
			//m_procState.ForceShowBizObj = true;
			//forceChildBizProcUpdates();
            clearDependentChildBizProcs();
			return selected;
		}

		protected virtual IBizObj setupSelectedBizObj(object keyValue, object source)
		{
			bool moreOne = false;
			object bizObjId = null;
			IBizObjDefinition def = App.bizObjMgr.getDefinition(BizObjTypeName);//SourceBizObjs.objectType;
			if (!Cmn.IsEmpty(keyValue))
			{
				if (moreOne = def.KeyFields.Count > 1)
					bizObjId = keyValue;
				else
					bizObjId = def.convertValueToKeyType(keyValue.ToString());
			}

            m_procState.put("prevId", m_procState.get("id"));
			m_procState.put("id", bizObjId);

			getCurrentBizObj();
			if (bizObjId != null && (m_currentBizObj == null ||
				(!moreOne && !m_currentBizObj.KeyValue.Equals(bizObjId)) ||
				(moreOne && bizObjId.ToString().CompareTo(m_currentBizObj.KeyValue.ToString()) == 0)) &&
                SourceBizObjs != null)
				m_currentBizObj = SourceBizObjs.search(SourceBizObjs.objectType.KeyFieldNames, bizObjId, false);
			m_retrievedCurrentBizObj = true;
			return m_currentBizObj;
		}

		protected virtual ParentBizProcInfo getCompletlyDependentParent()
		{
			foreach (ParentBizProcInfo pinfo in m_procState.OfflineState.ParentBizProcs.Values)
				if (pinfo.CompleteParentDependency)
					return pinfo;
			return null;
		}

		protected virtual bool IsFullyDependentForList { get { return getCompletlyDependentParent() != null; } }
		public virtual IBizObj createNewBizObj()
		{
			return BizObjTypeName==null?null:App.bizObjMgr.create(BizObjTypeName);
		}

		protected virtual string BizObjTypeName
		{
			get
			{
				return SourceBizObjs.objectType.Name;
			}
		}

		public void switchEditMode()
		{
			//m_procState.ForceShowBizObj = true;
			//this.showData(ForceLevel.mustShowGetDetailsDataIfNeeded);
            clearDependentChildBizProcs();
		}

		public void refreshListControls()
		{
			List<IBizObjListDisplay> listDisplays = m_procState.getListDisplays();
			if (listDisplays != null)
				foreach (IBizObjListDisplay ldisp in listDisplays)
					ldisp.refresh();
		}

		public void refreshData()
		{
			//m_procState.ForceShowBizObj = true;
			//this.showData(ForceLevel.mustShowGetDetailsDataIfNeeded);
            clearDependentChildBizProcs();
		}

		public virtual void addNewBizObj()
		{
            basicLog("addNewBizObj");
			IBizObj newBizObj = createNewBizObj();
			ParentBizProcInfo pinfo = getCompletlyDependentParent();
			if (pinfo != null)
				SourceBizObjs.Add(newBizObj);
			else
				State.InProgressAddBizObj = newBizObj;
			//m_procState.ForceShowBizObj = true;
			//forceChildBizProcUpdates();
            clearDependentChildBizProcs();
		}

        //protected virtual void forceChildBizProcUpdates()
        //{
        //   clearDependentChildBizProcs();
        //    //List<ActiveBizProc> children = m_procState.BPC.getDependentBizProcs(State.Id);
        //    //if (children != null)
        //    //    foreach (ActiveBizProc child in children)
        //    //    {
        //    //        if (child.BizProc is BaseBusinessProcess)
        //    //            ((BaseBusinessProcess)child.BizProc).updateActionState();
        //    //        //TODO: showData seems to be needed here, but is excessive.  The need comes from the fact that
        //    //        //we are dynamically generating controls based on showing a list of bizobjs in a complex bizobjlist
        //    //        //display.  If controls are created during the render process, they dont get processed properly 
        //    //        //in the BasebizObjDisplay due to the prerender being called immediately on creation of the controls.
        //    //        child.BizProc.showData(ForceLevel.mustShowForceDataRetrieval);
        //    //    }

        //}

        protected virtual void basicLog(string methodName)
        {
            string cbi = "";
			if (m_currentBizObj != null && m_currentBizObj.KeyValue != null)
				cbi = m_currentBizObj.KeyValue.ToString();
            App.Log.println(Swaf.Logging.LoggingLevels.Medium, "BizProc.{2}. BizProc.Id='{0}' CurrentBizObj.id='{1}'", Id, cbi, methodName);
        }

		protected virtual void forceParentBizProcUpdates()
		{
            basicLog("forceParentBizProcUpdates");
            foreach (ParentBizProcInfo parentInfo in m_procState.OfflineState.ParentBizProcs.Values)
			{
				ActiveBizProc parent = m_procState.BPC.getActiveBizProc(parentInfo.ParentId);
				if (parent.BizProc is BaseBusinessProcess)
					((BaseBusinessProcess)parent.BizProc).updateActionState();
				//TODO: showData seems to be needed here, but is excessive.  The need comes from the fact that
				//we are dynamically generating controls based on showing a list of bizobjs in a complex bizobjlist
				//display.  If controls are created during the render process, they dont get processed properly 
				//in the BasebizObjDisplay due to the prerender being called immediately on creation of the controls.
				parent.BizProc.showData(ForceLevel.mustShowForceDataRetrieval);
			}
		}

		protected virtual void forceAllBizProcUpdates()
		{
            basicLog("forceAllBizProcUpdates");
			foreach (BizProcOfflineState offlineState in m_procState.BPC.PageState.BizProcStates.Values)
			{
				ActiveBizProc active = m_procState.BPC.getActiveBizProc(offlineState.Id);
				//TODO: showData seems to be needed here, but is excessive.  The need comes from the fact that
				//we are dynamically generating controls based on showing a list of bizobjs in a complex bizobjlist
				//display.  If controls are created during the render process, they dont get processed properly 
				//in the BasebizObjDisplay due to the prerender being called immediately on creation of the controls.
				active.BizProc.showData(ForceLevel.mustShowForceDataRetrieval);
			}
		}

		protected bool isAllTypeChild(BizProcOfflineState bizProcState)
		{
			foreach (ParentBizProcInfo pinfo in bizProcState.ParentBizProcs.Values)
				if (pinfo.ParentId == "_all")
					return true;
			return false;
		}

		public virtual void updateBizObj()
		{
			updateBizObj(false);
		}

		public virtual void updateBizObj(bool refreshOnly)
		{
            basicLog("updateBizObj");
			List<ActiveBizProc> children = m_procState.BPC.getDependentBizProcs(State.Id);
			if (children != null)
				foreach (ActiveBizProc child in children)
					foreach (ParentBizProcInfo pinfo in child.OfflineState.ParentBizProcs.Values)
						if (pinfo.ParentId == Id && pinfo.CompleteParentDependency)
						{
							pinfo.ParentSelectedBizObjFieldValueCache = null;
							child.BizProc.updateBizObj();
						}

			List<IBizObjDisplay> detailDisplays = m_procState.getDetailsDisplays();
			if (detailDisplays != null && detailDisplays.Count != 0)
			{
				foreach (IBizObjDisplay disp in detailDisplays)
				{
					disp.EditPrivilege = CanEdit ? CurrentEditPrivilege : Privileges.ReadOnly;
					disp.updateBizObj(CurrentBizObj);
				}
			}

			object newKey = null;
			IBizObj current = CurrentBizObj;
			if (current != null && validateBizObj(current))
			{
				newKey = (current.isNew) ? current.KeyValue : null;
				if (!refreshOnly)
					updateBizObj(current);
			}
			if(!refreshOnly)
				clearRetrievedData();

			if (SourceBizObjs != null)
			{
				IBizObjCursor cur = SourceBizObjs.createCursor();
				List<IBizObjListDisplay> listDisplays = m_procState.getListDisplays();
				if (listDisplays != null && listDisplays.Count != 0)
					foreach (IBizObjListDisplay disp in listDisplays)
					{
						disp.showBizObjs(cur);
						disp.updateBizObjs();
					}
			}
			if (!refreshOnly)
			{
				//If an add was happening, clear it out after updating.
				State.InProgressAddBizObj = null;
				getBizObjList();
				if (newKey != null && m_bizobjs != null)
					selectBizObj(newKey, null);
			}

			//forceChildBizProcUpdates();
            //clearDependentChildBizProcs();
		}

		protected virtual bool validateBizObj(IBizObj obj)
		{
			List<ValidationError> errors = obj.validate();
			if (!(errors == null || errors.Count == 0))
			{
				m_hadValidationErrors = true;
				foreach (ValidationError e in errors)
					m_procState.BPC.Messenger.add("Error-InvalidParameter", e);
				return false;
			}
			return true;
		}
		
		public virtual IResults updateBizObj(IBizObj obj)
		{
			IResults rc = null;
			if (validateBizObj(obj))
				if (!Cmn.IsEmpty(m_updateBizObjRule))
				{
					//m_procState.ForceShowBizObj = true;
					rc = App.ruleMgr.execute(m_updateBizObjRule, getUpdateBizRuleParameters(obj));
					if (rc.CallResults != null && rc.ExceptionInfo == null && rc.CallResults is IBizObj)
						m_currentBizObj = (IBizObj)rc.CallResults;
					clearDependentChildBizProcs();
				}
				else
				{
					if (obj.isNew)
					{
						if (SourceBizObjs.search(SourceBizObjs.objectType.KeyFieldNames, obj.KeyValue) == null)
						{
							SourceBizObjs.Add(obj);
							SourceBizObjs.refreshIndexesFromBizObj(obj);
							clearDependentChildBizProcs();
						}
					}
				}
			return rc;
		}

		public virtual void deleteBizObj()
		{
			object key = m_procState.get("id");
			deleteBizObj(key);
			//getBizObjList();
			//forceChildBizProcUpdates();
			clearRetrievedData();
            clearDependentChildBizProcs();
		}

		public virtual void deleteBizObj(object key)
		{
			if (!Cmn.IsEmpty(m_deleteBizObjRule))
			{
				IResults rc = App.ruleMgr.execute(m_deleteBizObjRule, getDeleteRuleParameters(key));
				m_procState.put("id", null);
			}
			else
			{
				if(SourceBizObjs != null)
				{
					int num = SourceBizObjs.numElements;
					for(int p = 0; p < num; p++)
						if(((IComparable)SourceBizObjs[p].KeyValue).CompareTo(key) == 0)
						{
							SourceBizObjs.RemoveAt(p);
							break;
						}
				}
			}
		}

		protected virtual object convertValueToKeyType(object val)
		{
			return (SourceBizObjs == null || val == null) ? val : SourceBizObjs.objectType.convertValueToKeyType(val.ToString());
		}
		

		public void moveToLast()
		{
		}

		public void moveToFirst()
		{
		}

		public virtual void moveNext()
		{
			if (SourceBizObjs == null)
				return;
			object bizObjId = m_procState.get("id");
			if (bizObjId == null && SourceBizObjs != null && SourceBizObjs.numElements != 0)
				bizObjId = SourceBizObjs[0].KeyValue;
			bizObjId = convertValueToKeyType(bizObjId);// SourceBizObjs.objectType.convertValueToKeyType(bizObjId.ToString());
			for (int index = 0; index < SourceBizObjs.numElements; index++)
			{
				IComparable key = SourceBizObjs[index].KeyValue as IComparable;
				if(key != null && key.CompareTo(bizObjId) == 0)
				{
					index = (index == SourceBizObjs.numElements - 1) ? 0 : index + 1;
					m_procState.put("id", SourceBizObjs[index].KeyValue);
					getCurrentBizObj();
					//m_procState.ForceShowBizObj = true;
					//forceChildBizProcUpdates();
                    clearDependentChildBizProcs();
					return;
				}
			}
		}

		public virtual void movePrev()
		{
			if (SourceBizObjs == null)
				return;
			object bizObjId = m_procState.get("id");
			if (bizObjId == null && SourceBizObjs != null && SourceBizObjs.numElements != 0)
				bizObjId = SourceBizObjs[0].KeyValue;
			bizObjId = convertValueToKeyType(bizObjId); //SourceBizObjs.objectType.convertValueToKeyType(bizObjId.ToString());
			for (int index = SourceBizObjs.numElements-1; index >= 0 ; index--)
				if (SourceBizObjs[index].KeyValue.Equals(bizObjId))
				{
					index = (index == 0) ? SourceBizObjs.numElements - 1 : index - 1;
					m_procState.put("id", SourceBizObjs[index].KeyValue);
					getCurrentBizObj();
					//m_procState.ForceShowBizObj = true;
					//forceChildBizProcUpdates();
                    clearDependentChildBizProcs();
					return;
				}
		}

		public virtual void cancelEdits()
		{
			State.InProgressAddBizObj = null;
			//m_procState.ForceShowBizObj = true;
			getCurrentBizObj();
			//forceChildBizProcUpdates();
            clearDependentChildBizProcs();
		}

		public virtual void changeMasterDataOption()
		{
			IBizObjList objs = SourceBizObjs;
			if (objs != null && objs is MasterBaseBizObjList)
			{
				MasterBaseBizObjList mb = (MasterBaseBizObjList)objs;
				if (MasterDataDisplayOption == MasterBaseBizObjListDisplayOption.blended)
					mb.MasterVisibility = MasterDataDisplayOption = MasterBaseBizObjListDisplayOption.blOnly;
				else
					mb.MasterVisibility = MasterDataDisplayOption = MasterBaseBizObjListDisplayOption.blended;

			}
		}

		protected abstract void setupRuleNames();

		protected virtual void setupActions()
		{
			Actions.addAction(new GenericAction("SwitchEdit", true, switchEditMode, this));
			Actions.addAction(new GenericAction("RefreshData", true, refreshData, this));
			Actions.addAction(new GenericAction("AddBizObj", false, addNewBizObj, this));
			Actions.addAction(new GenericAction("UpdateBizObj", false, updateBizObj, this));
			Actions.addAction(new GenericAction("DeleteBizObj", false, deleteBizObj, this));
			Actions.addAction(new GenericAction("MoveToFirst", true, moveToLast, this));
			Actions.addAction(new GenericAction("MoveToLast", true, moveToLast, this));
			Actions.addAction(new GenericAction("MoveNext", true, moveNext, this));
			Actions.addAction(new GenericAction("MovePrev", true, movePrev, this));
			Actions.addAction(new GenericAction("MasterDataOption", false, changeMasterDataOption, this));

			Actions.addAction(new GenericAction("CancelEdits", false, cancelEdits, this));
			((GenericAction)Actions["CancelEdits"]).Availability = ActionAvailability.none;
		}

		//----------------------------------------------------------------------------------------------
		protected IApplication App
		{
			get
			{
				return Application.currentApp;
			}
		}

		protected ISecurityPrincipal CurrentPrincipal
		{
			get
			{
				Debug.Assert(App.securityMgr.currentPrincipal != null);
				return App.securityMgr.currentPrincipal;
			}
		}
		protected IBizObj CurrentUser
		{
			get
			{
				Debug.Assert(App.securityMgr.currentPrincipal.additionalInfo != null);
				Debug.Assert(App.securityMgr.currentPrincipal.additionalInfo is IBizObj);
				return CurrentPrincipal.additionalInfo as IBizObj;
			}
		}

		protected Swaf.BGuid.Guid CurrentCompanyId
		{
			get
			{
				Debug.Assert(CurrentUser.get("companyId") != null);
				Debug.Assert(CurrentUser.get("companyId") is Swaf.BGuid.Guid);
				return (Swaf.BGuid.Guid)CurrentUser.get("companyId");
			}
		}

		protected Swaf.BGuid.Guid ActiveCompanyId
		{
			get
			{
				Debug.Assert(CurrentUser.get("activeCompanyId") != null);
				Debug.Assert(CurrentUser.get("activeCompanyId") is Swaf.BGuid.Guid);
				return (Swaf.BGuid.Guid)CurrentUser.get("activeCompanyId");
			}
		}
		protected IBizObj ActiveCompany
		{
			get
			{
				return App.ruleMgr.execute("getCachedCompanyInfo", ActiveCompanyId).CallResults as IBizObj;
			}
		}

		protected void displayMessage(string msgId)
		{
			m_procState.BPC.Messenger.add(msgId, null);
		}
		protected void displayMessage(string msgId, INameAddressSupport replacements)
		{
			m_procState.BPC.Messenger.add(msgId, replacements);
		}
		protected void displayMessageFromBizRuleException(string msgId, Exception e, params object[] repInfo)
		{
			FlexiMap replacements = new FlexiMap();
			replacements.put("ErrorClass", e.GetType().Name);
			replacements.put("ErrorMessage", e.Message);
			if(e is BaseException)
				replacements.put("FullErrorTrace", ((BaseException)e).FullExceptionString);
			if (repInfo != null)
			{
				Debug.Assert(repInfo.Length % 2 == 0);
				int c = repInfo.Length;
				for (int pos = 0; pos < c; pos++)
					replacements.put(repInfo[pos].ToString(), repInfo[++pos]);
			}
			m_procState.BPC.Messenger.add("Error-BizRuleSystemError", replacements);
		}

		//protected void OnBizProcException(object theObj, string methodName, Exception e)
		//{
		//    if (BizProcException != null)
		//        BizProcException(this, methodName, e);
		//}
		//public event BPException BizProcException;

		public static Dictionary<string, int> ShowDataCounts = null;
		public static void resetShowDataCounts()
		{
			ShowDataCounts = new Dictionary<string, int>();
		}

		public static void incrementCount(string id)
		{
			if (!ShowDataCounts.ContainsKey(id))
				ShowDataCounts[id] = 1;
			else
				ShowDataCounts[id] += 1;
		}
	}

	public enum MasterDataOption { unknown, none, listFromParentBizProc, listFromRule };
}
